home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
TEMP
/
GNU
/
flex
/
Actions
< prev
next >
Wrap
Text File
|
1995-06-28
|
9KB
|
284 lines
Actions
Previous: <Matching=>Matching> * Next: <Generated scanner=>Generateds> * Up: <Top=>!Root>
#Wrap on
{fH3}Actions{f}
Each pattern in a rule has a corresponding action, which
can be any arbitrary C statement. The pattern ends at the
first non-escaped whitespace character; the remainder of
the line is its action. If the action is empty, then when
the pattern is matched the input token is simply
discarded. For example, here is the specification for a
program which deletes all occurrences of "zap me" from its
input:
#Wrap off
#fCode
%%
"zap me"
#f
#Wrap on
(It will copy all other characters in the input to the
output since they will be matched by the default rule.)
Here is a program which compresses multiple blanks and
tabs down to a single blank, and throws away whitespace
found at the end of a line:
#Wrap off
#fCode
%%
[ \\t]+ putchar( ' ' );
[ \\t]+$ \/\* ignore this token \*\/
#f
#Wrap on
If the action contains a '\{', then the action spans till
the balancing '\}' is found, and the action may cross
multiple lines. {fCode}flex{f} knows about C strings and comments and
won't be fooled by braces found within them, but also
allows actions to begin with {fEmphasis}%\{{f} and will consider the
action to be all the text up to the next {fEmphasis}%\}{f} (regardless of
ordinary braces inside the action).
An action consisting solely of a vertical bar ('|') means
"same as the action for the next rule." See below for an
illustration.
Actions can include arbitrary C code, including {fCode}return{f}
statements to return a value to whatever routine called
{fEmphasis}yylex(){f}. Each time {fEmphasis}yylex(){f} is called it continues
processing tokens from where it last left off until it either
reaches the end of the file or executes a return.
Actions are free to modify {fCode}yytext{f} except for lengthening
it (adding characters to its end--these will overwrite
later characters in the input stream). This however does
not apply when using {fEmphasis}%array{f} (see above); in that case,
{fCode}yytext{f} may be freely modified in any way.
Actions are free to modify {fCode}yyleng{f} except they should not
do so if the action also includes use of {fEmphasis}yymore(){f} (see
below).
There are a number of special directives which can be
included within an action:
#Indent +4
- {fEmphasis}ECHO{f} copies yytext to the scanner's output.
- {fCode}BEGIN{f} followed by the name of a start condition
places the scanner in the corresponding start
condition (see below).
- {fCode}REJECT{f} directs the scanner to proceed on to the
"second best" rule which matched the input (or a
prefix of the input). The rule is chosen as
described above in "How the Input is Matched", and
{fCode}yytext{f} and {fCode}yyleng{f} set up appropriately. It may
either be one which matched as much text as the
originally chosen rule but came later in the {fCode}flex{f}
input file, or one which matched less text. For
example, the following will both count the words in
the input and call the routine special() whenever
"frob" is seen:
#Wrap off
#fCode
int word\_count = 0;
%%
frob special(); REJECT;
[^ \\t\\n]+ ++word\_count;
#f
#Wrap on
Without the {fCode}REJECT{f}, any "frob"'s in the input would
not be counted as words, since the scanner normally
executes only one action per token. Multiple
{fCode}REJECT's{f} are allowed, each one finding the next
best choice to the currently active rule. For
example, when the following scanner scans the token
"abcd", it will write "abcdabcaba" to the output:
#Wrap off
#fCode
%%
a |
ab |
abc |
abcd ECHO; REJECT;
.|\\n \/\* eat up any unmatched character \*\/
#f
#Wrap on
(The first three rules share the fourth's action
since they use the special '|' action.) {fCode}REJECT{f} is
a particularly expensive feature in terms of
scanner performance; if it is used in {fEmphasis}any{f} of the
scanner's actions it will slow down {fEmphasis}all{f} of the
scanner's matching. Furthermore, {fCode}REJECT{f} cannot be used
with the {fEmphasis}-Cf{f} or {fEmphasis}-CF{f} options (see below).
Note also that unlike the other special actions,
{fCode}REJECT{f} is a {fEmphasis}branch{f}; code immediately following it
in the action will {fEmphasis}not{f} be executed.
- {fEmphasis}yymore(){f} tells the scanner that the next time it
matches a rule, the corresponding token should be
{fEmphasis}appended{f} onto the current value of {fCode}yytext{f} rather
than replacing it. For example, given the input
"mega-kludge" the following will write
"mega-mega-kludge" to the output:
#Wrap off
#fCode
%%
mega- ECHO; yymore();
kludge ECHO;
#f
#Wrap on
First "mega-" is matched and echoed to the output.
Then "kludge" is matched, but the previous "mega-"
is still hanging around at the beginning of {fCode}yytext{f}
so the {fEmphasis}ECHO{f} for the "kludge" rule will actually
write "mega-kludge".
#Indent
Two notes regarding use of {fEmphasis}yymore(){f}. First, {fEmphasis}yymore(){f}
depends on the value of {fCode}yyleng{f} correctly reflecting the
size of the current token, so you must not modify {fCode}yyleng{f}
if you are using {fEmphasis}yymore(){f}. Second, the presence of
{fEmphasis}yymore(){f} in the scanner's action entails a minor
performance penalty in the scanner's matching speed.
#Indent +4
- {fEmphasis}yyless(n){f} returns all but the first {fStrong}n{f} characters of
the current token back to the input stream, where
they will be rescanned when the scanner looks for
the next match. {fCode}yytext{f} and {fCode}yyleng{f} are adjusted
appropriately (e.g., {fCode}yyleng{f} will now be equal to {fStrong}n{f}
). For example, on the input "foobar" the
following will write out "foobarbar":
#Wrap off
#fCode
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;
#f
#Wrap on
An argument of 0 to {fCode}yyless{f} will cause the entire
current input string to be scanned again. Unless
you've changed how the scanner will subsequently
process its input (using {fCode}BEGIN{f}, for example), this
will result in an endless loop.
Note that {fCode}yyless{f} is a macro and can only be used in the
flex input file, not from other source files.
- {fEmphasis}unput(c){f} puts the character {fCode}c{f} back onto the input
stream. It will be the next character scanned.
The following action will take the current token
and cause it to be rescanned enclosed in
parentheses.
#Wrap off
#fCode
\{
int i;
\/\* Copy yytext because unput() trashes yytext \*\/
char \*yycopy = strdup( yytext );
unput( ')' );
for ( i = yyleng - 1; i >= 0; --i )
unput( yycopy[i] );
unput( '(' );
free( yycopy );
\}
#f
#Wrap on
Note that since each {fEmphasis}unput(){f} puts the given
character back at the {fEmphasis}beginning{f} of the input stream,
pushing back strings must be done back-to-front.
An important potential problem when using {fEmphasis}unput(){f} is that
if you are using {fEmphasis}%pointer{f} (the default), a call to {fEmphasis}unput(){f}
{fEmphasis}destroys{f} the contents of {fCode}yytext{f}, starting with its
rightmost character and devouring one character to the left
with each call. If you need the value of yytext preserved
after a call to {fEmphasis}unput(){f} (as in the above example), you
must either first copy it elsewhere, or build your scanner
using {fEmphasis}%array{f} instead (see How The Input Is Matched).
Finally, note that you cannot put back {fCode}EOF{f} to attempt to
mark the input stream with an end-of-file.
- {fEmphasis}input(){f} reads the next character from the input
stream. For example, the following is one way to
eat up C comments:
#Wrap off
#fCode
%%
"\/\*" \{
register int c;
for ( ; ; )
\{
while ( (c = input()) != '\*' &&
c != EOF )
; \/\* eat up text of comment \*\/
if ( c == '\*' )
\{
while ( (c = input()) == '\*' )
;
if ( c == '\/' )
break; \/\* found the end \*\/
\}
if ( c == EOF )
\{
error( "EOF in comment" );
break;
\}
\}
\}
#f
#Wrap on
(Note that if the scanner is compiled using {fEmphasis}C++{f},
then {fEmphasis}input(){f} is instead referred to as {fEmphasis}yyinput(){f},
in order to avoid a name clash with the {fEmphasis}C++{f} stream
by the name of {fCode}input{f}.)
- flushes the scanner's internal buffer so that the next time the scanner
attempts to match a token, it will first refill the buffer using
{fCode}YY\_INPUT{f} (see The Generated Scanner, below). This action is
a special case of the more general {fEmphasis}yy\_flush\_buffer(){f} function,
described below in the section Multiple Input Buffers.
- {fEmphasis}yyterminate(){f} can be used in lieu of a return
statement in an action. It terminates the scanner
and returns a 0 to the scanner's caller, indicating
"all done". By default, {fEmphasis}yyterminate(){f} is also
called when an end-of-file is encountered. It is a
macro and may be redefined.
#Indent